-- Copyright (c) 2025 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at:
--         http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

local class = require 'mc.class'
local singleton = require 'mc.singleton'
local log = require 'mc.logging'
local skynet = require 'skynet'
local service_ok, cnc_server_instance = pcall(require, 'mc.cnc.server')
local tcp_mgmt_instance = require 'tcp.tcp_mgmt'

local module = class{}

function module:ctor()
    -- 默认为空函数避免报错
    self.sync_propery_callback = function(...)
    end
    self.sync_file_callback = function(...)
    end
    self.cnc_service = nil
end

-- 根据TCP同步使能状态更新所有客户端
function module:update_cnc_service(name, value)
    -- 服务端不响应角色变化
    if name ~= 'Enabled' then
        return
    end
    if value then
        self:create_cnc_service()
    elseif self.cnc_service then
        self.cnc_service:destroy()
        self.cnc_service = nil
    end
end

-- IP地址发生变更后需要重新建立服务端
function module:update_service_address()
    if tcp_mgmt_instance:get_instance().tcp_enabled and self.cnc_service then
        self.cnc_service:destroy()
        self.cnc_service = nil
    end
    self:create_cnc_service()
    log:notice('service config address change to [%s]', tcp_mgmt_instance:get_instance().service_address)
end

function module:register(tcp_sig, address_sig)
    -- 注册回调
    tcp_sig:on(function(name, value)
        self:update_cnc_service(name, value)
    end)
    address_sig:on(function(address)
        self:update_service_address(address)
    end)

    if tcp_mgmt_instance:get_instance().tcp_enabled then
        self:create_cnc_service()
    end
end

function module:register_callback(property_cb, file_cb)
    self.sync_propery_callback = property_cb
    self.sync_file_callback = file_cb
end

function module:create_cnc_service()
    if self.cnc_service then
        return
    end
    if not service_ok then
        log:info('require setvice failed, err %s', cnc_server_instance)
        return
    end
    local ok, err
    local try_count = 0  --  统计重试次数（默认0）
    while not ok and try_count ~= 60 do  -- 重试60次（10分钟）
        ok, err = pcall(function()
            self.cnc_service = cnc_server_instance.new(tcp_mgmt_instance:get_instance().service_address)
        end)
        if ok then
            break
        end
        if try_count % 10 == 0 then  -- 取10的余数，等于0打印日志，即每重试10次打印一次
            log:error('create cnc server failed, %s', err)
        end
        try_count = try_count + 1
        skynet.sleep(1000)  -- 间隔10秒重试，服务刚启动时可能失败（1000表征10秒）
    end
    if not ok then
        return
    end
    log:notice('create cnc server success, try_count: [%s]', try_count)
    -- 注册回调函数
    cnc_server_instance.on_call_remote_class_method(function(service_name, path, interface, method, signalure, ctx, datas)
        -- 校验数据是否合法
        if method == 'UpdateProperty' then
            -- 更新数据
            self.sync_propery_callback(datas)
        elseif method == 'UpdateFile' then
            self.sync_file_callback(datas)
        end
    end)
end

return singleton(module)